package com.lxy.web;

import com.lxy.bean.Menu;
import com.lxy.bean.Permission;
import com.lxy.bean.Role;
import com.lxy.bean.User;
import com.lxy.config.shiro.CustomUsernamePasswordToken;
import com.lxy.config.shiro.exception.InvalidLoginPageException;
import com.lxy.config.shiro.exception.ValidCodeException;
import com.lxy.service.PermissionService;
import com.lxy.service.RoleService;
import com.lxy.service.UserService;
import com.lxy.util.JsonUtilTools;
import com.lxy.util.ValidateCode;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

/**
 * Created by zl on 2016/12/13.
 */
@Controller
@RequestMapping("/")
public class LoginController {


    private Logger logger = Logger.getLogger(getClass());

    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private PermissionService permissionService;

    @RequestMapping("login")
    public String index() {
        Subject subject = SecurityUtils.getSubject();
        // 已登陆则 跳到首页
        if (subject.isAuthenticated()) {
            return "redirect:/home";
        }
        return "/login";
    }

    /**
     * @param
     * @return 设定文件 String 返回类型 @throws
     * @Title: loginValidate
     * @Description: 登录校验
     */
    @RequestMapping(value = "loginValidate", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> loginValidate(User user, String vcode, String validateType, HttpServletRequest request) {
        Map<String, Object> result = new HashMap<String, Object>();
        HttpSession session = request.getSession(true);
        result.put("msg", "用户名或者密码错误!");
        result.put("success", "true");
        result.put("target", "username");
        try {
            Subject subject = SecurityUtils.getSubject();
            // 已登陆则 跳到首页
            if (subject.isAuthenticated()) {
                if (session.getAttribute("userInfo") != null) {
                    if (((User) session.getAttribute("userInfo")).getUserName().equals(user.getUserName())) {
                        result.put("msg", "用户登录验证通过!");
                        result.put("target", "0");
                        // 显式调用，执行权限分配
                        SecurityUtils.getSubject().getPrincipals();
                        return result;
                    } else {
                        result.put("msg", ((User) session.getAttribute("userInfo")).getUserName() + "已登录，请退出后再登录新账号!");
                        result.put("target", "username");
                        return result;
                    }
                } else {
                    return result;
                }
            } else {
                boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
                String host = request.getRemoteHost();

                String userName = user.getUserName();
                if (userName == null || "".equals(userName)) {
                    result.put("msg", "用户名不能为空!");
                    result.put("target", "username");
                }
                String password = user.getUserPassword();
                if (password == null || "".equals(password)) {
                    result.put("msg", "用户密码不能为空!");
                    result.put("target", "password");
                }
                if (vcode == null || "".equals(vcode)) {
                    result.put("msg", "用户验证码不能为空!");
                    result.put("target", "vcode");
                }

                // 构造登陆令牌环
                CustomUsernamePasswordToken token = new CustomUsernamePasswordToken(userName, password.toCharArray(),
                        rememberMe, host, vcode, validateType);

                // 发出登陆请求
                SecurityUtils.getSubject().login(token);
                // 获得登录用户信息
                user = userService.getUserByUserName(userName);
                if (user != null) {
                    if (SecurityUtils.getSubject().isAuthenticated()) {
                        subject = SecurityUtils.getSubject();
                        result.put("msg", "用户登录验证通过!");
                        result.put("target", "0");
                        // 通过用户id查询用户拥有角色
                        List<Role> roleInfos = roleService.getRolesByUserId(user.getId());
                        user.setRoles(new HashSet<>(roleInfos));

                        Set<Permission> permissions = new HashSet<Permission>();
                        // 获取每个角色对应的权限
                        for (Role role : roleInfos) { // 添加角色
                            List<Permission> rolePermissions = permissionService.getPermissionByRoleId(role.getId());
                            permissions.addAll(rolePermissions);
                        }
                        user.setPermissions(new ArrayList<>(permissions));
                        // 初始化角色菜单
                       /* List<Menu> treeNodes = new ArrayList<>();
                        for (Permission permission : permissions) {
                            com.lxy.core.model.Resource r = permission.getPermissionInfo();
                            if (r != null
                                    && r.getState() == 1) {
                                Menu menu = new Menu(permission.getId(), r.getResName(), r.getResIcon(), r.getResUrl(),
                                        r.getResType(), permission.getSort(), "open", permission.getpId());
                                treeNodes.add(menu);
                            }
                        }
                        Collections.sort(treeNodes);
                        user.setMenus(formatterResource(treeNodes));*/
                    }
                    // 把登录成功的用户放入缓存
                    session.setAttribute("userInfo", user);
                    subject.getSession().setAttribute("userInfo", user);
                }
            }
        } catch (UnknownAccountException e) {
            result.put("msg", e.getMessage());
            logger.debug(e.getMessage());
        } catch (IncorrectCredentialsException e) {
            result.put("msg", e.getMessage());
            result.put("target", "password");
            logger.debug("用户或者密码错误");
        } catch (ExcessiveAttemptsException e) {
            result.put("msg", e.getMessage());
            logger.debug(e.getMessage());
        } catch (ValidCodeException e) {
            result.put("msg", e.getMessage());
            result.put("target", "vcode");
            logger.debug(e.getMessage());
        } catch (InvalidLoginPageException e) {
            result.put("msg", e.getMessage());
            result.put("target", "username");
            logger.debug(e.getMessage());
        } catch (LockedAccountException e) {
            result.put("msg", e.getMessage());
            logger.debug(e.getMessage());
        } catch (AuthenticationException e) {
            result.put("msg", "系统错误");
            logger.debug("系统错误");
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 资源格式化
     *
     * @param userAllResList
     * @return
     */
    public static List<Menu> formatterResource(List<Menu> userAllResList) {
        List<Menu> resList = new ArrayList<Menu>();
        List<Menu> pl = new Vector<Menu>(userAllResList.size());
        Map<Integer, Menu> resMap = new HashMap<Integer, Menu>();
        for (Menu rs : userAllResList) {
            if (rs != null && !resMap.containsKey(rs.getId())) {
                pl.add(rs);
                resMap.put(rs.getId(), rs);
            }
        }
        for (Menu rs : pl) {
            if (rs.getParentId() == 0) {// 根节点
                resList.add(rs);
            } else {
                Menu parent = resMap.get(rs.getParentId());// 设置孩子节点
                if (parent != null) {
                    parent.getChildren().add(rs);
                    parent.setState("open");// 有子节点
                }
            }
        }
        return resList;
    }

    /**
     * 生成图片验证码
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "checkCode", method = RequestMethod.GET)
    public void createCheckCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置响应的类型格式为图片格式
        System.out.println(request.getSession() + "=session");
        int width = 140;
        int height = 36;
        int codeCount = 4;
        int lineCount = 20;
        if (request.getParameter("width") != null) {
            width = Integer.parseInt(request.getParameter("width"));
        }
        if (request.getParameter("height") != null) {
            height = Integer.parseInt(request.getParameter("height"));
        }
        if (request.getParameter("codeCount") != null) {
            codeCount = Integer.parseInt(request.getParameter("codeCount"));
        }
        if (request.getParameter("lineCount") != null) {
            height = Integer.parseInt(request.getParameter("lineCount"));
        }
        response.setContentType("image/jpeg");
        // 禁止图像缓存。
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        ValidateCode vCode = new ValidateCode(width, height, codeCount, lineCount);
        SecurityUtils.getSubject().getSession().setAttribute("loginCode", vCode.getCode());
        vCode.write(response.getOutputStream());
    }

    @RequestMapping("logout")
    @ResponseBody
    public String logout(HttpSession session) {
        SecurityUtils.getSubject().logout();
        return "success";
    }

    @RequestMapping("home")
    public String home(Model model, HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        // 返回当前用户信息
        model.addAttribute("loginUser", session.getAttribute("userInfo"));
        String userJson = JsonUtilTools.toJson((User) session.getAttribute("userInfo"));
        model.addAttribute("loginUserJson", userJson);
        List<Permission> permissions = getMenuPanels(request, response, session);
        if (permissions == null || permissions.size() == 0) {
            logger.error("用户非法访问后台");
            return "redirect:/login";
        }
        model.addAttribute("userMenuPanel", permissions);
        return "home";
    }

    /**
     * @Title: getMenuPanels @Description: 获得用户菜单面板信息 @param @param
     * request @param @param response @param @param
     * userName @param @return 设定文件 @return List<Map<String,Object>>
     * 返回类型 @throws
     */
    @RequestMapping("userMenuPanelData")
    @ResponseBody
    public List<Permission> getMenuPanels(HttpServletRequest request, HttpServletResponse response,
                                          HttpSession session) {
        List<Permission> panelList = new ArrayList<Permission>();
        System.out.println(session.getAttribute("userInfo"));
        List<Permission> permissions = ((User) session.getAttribute("userInfo")).getPermissions();
        for (Permission permission : permissions) {
            if (permission.getParentPermission() == null) {// 没有父节点
                panelList.add(permission);
            }
        }
        Collections.sort(permissions);
        return panelList;
    }

    /**
     * @param request
     * @param response
     * @param session
     * @param id
     * @return
     * @Description TODO(实例化树结点)
     * @author lxy
     * @date 2016年10月13日 下午4:46:37
     */
    @RequestMapping("userMenuTreeNode")
    @ResponseBody
    public List<Menu> getMenuTreeNode(HttpServletRequest request, HttpServletResponse response, HttpSession session,
                                      int id) {
        //获取所有子节点
        List<Permission> permissions = permissionService.selectByPId(id);
        List<Menu> treeNodes = new ArrayList<>();
        for (Permission permission : permissions) {
            com.lxy.bean.Resource r = permission.getPermissionInfo();
            if (r != null && r.getState() == 1) {
                Menu menu = new Menu(permission.getId(), r.getResName(), r.getResIcon(), r.getResUrl(),
                        r.getResType(), permission.getSort(), "open", permission.getpId());
                treeNodes.add(menu);
            }
        }
        Collections.sort(treeNodes);
        return treeNodes;
    }

    /**
     * @param @param  pagePath
     * @param @return 设定文件
     * @return String    返回类型
     * @throws
     * @Title: findPage
     * @Description: 定义公共返回页面的controller
     */
    @RequestMapping("findPage/{pageName}")
    public String findPage(@PathVariable("pageName") String pageName) {
        return "page" + "/" + pageName;
    }
}
